package com.sky.rabc.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sky.rabc.common.RedissonCommon;
import com.sky.rabc.dto.order.*;
import com.sky.rabc.enums.OrderStatus;
import com.sky.rabc.enums.PayStatus;
import com.sky.rabc.enums.PayType;
import com.sky.rabc.enums.ServiceCode;
import com.sky.rabc.exception.ServiceException;
import com.sky.rabc.mapper.*;
import com.sky.rabc.service.OrderService;
import com.sky.rabc.utils.AesCommon;
import com.sky.rabc.utils.NumberGenerator;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
    @Value("${rabc.aes.key}")
    private String aesKey;
    @Value("${rabc.aes.iv}")
    private String aesIv;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private ApplicationContext applicationContext;
    private final AddressMapper addressMapper;
    private final ObjectMapper objectMapper;
    private final ProductMapper productMapper;
    private final ProductDetailsMapper productDetailsMapper;
    private final OrderDetailsMapper orderDetailsMapper;
    private final OrderMapper orderMapper;
    private final PayInfoMapper payInfoMapper;
    private final RedissonCommon redissonCommon;

    public OrderServiceImpl(AddressMapper addressMapper, ObjectMapper objectMapper, ProductMapper productMapper, ProductDetailsMapper productDetailsMapper, OrderDetailsMapper orderDetailsMapper, OrderMapper orderMapper, PayInfoMapper payInfoMapper, RedissonCommon redissonCommon) {
        this.addressMapper = addressMapper;
        this.objectMapper = objectMapper;
        this.productMapper = productMapper;
        this.productDetailsMapper = productDetailsMapper;
        this.orderDetailsMapper = orderDetailsMapper;
        this.orderMapper = orderMapper;
        this.payInfoMapper = payInfoMapper;
        this.redissonCommon = redissonCommon;
    }

    /**
     * 创建订单
     *
     * @param createOderDTO 创建订单DTO
     */
    @Override
    public void createOrder(CreateOderDTO createOderDTO) {
        CreatOrderDTO creatOrderDTO = ConfigCreatOrderData(createOderDTO);
        //获取当前类的代理对象
        OrderServiceImpl orderService = applicationContext.getBean(OrderServiceImpl.class);
        //执行数据插入
        transactionTemplate.executeWithoutResult(transactionStatus -> {
            try {
                //扣减库存
                orderService.amountDeducted(creatOrderDTO.getBuyDetailsProduct());
                payInfoMapper.insert(creatOrderDTO.getAddNewPayInfoDTO());
                orderDetailsMapper.batchInsert(creatOrderDTO.getAddNewOrderDetailsDTOS());
                productDetailsMapper.batchInsert(creatOrderDTO.getAfterConfigureNewAddNewProductDetailsList());
                //装配添加新订单DTO
                AddNewOrderDTO addNewOrderDTO = configureAddNewOrderDTO(creatOrderDTO);
                orderMapper.insert(addNewOrderDTO);
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                log.info("创建订单失败");
                throw new ServiceException(ServiceCode.ERROR_INSERT, "创建订单失败");
            }
        });
    }

    /**
     * 配置创建订单数据
     *
     * @param createOderDTO 创建订单数据DTO
     * @return CreatOrderDTO
     */
    private CreatOrderDTO ConfigCreatOrderData(CreateOderDTO createOderDTO) {
        Long userId = createOderDTO.getUserId();
        List<BuyProductDTO> buyDetailsProduct = createOderDTO.getBuyDetailsProduct();
        // 生成主订单编号(20位) = 创建订单时间(10位)+订单详情数(4位)+当天订单序列号(5位)
        BigInteger orderId = createOrderId(buyDetailsProduct.size());
        // 获取用户启用id
        Long userAddressId = getUserAddressId(userId);
        //配置支付信息
        AddNewPayInfoDTO addNewPayInfoDTO = configurePayInfo(orderId);
        // 设置订单token，并存入redis中，30分钟过期,未结束订单的一系列数据销毁
        String orderToken = addNewOrderToken(orderId, userId);
        //配置购买商品详情快照List
        List<AddNewProductDetailsDTO> beforeConfigureNewAddNewProductDetailsDTOS = beforeConfigureNewAddNewProductDetailsList(buyDetailsProduct);
        //配置店铺订单详情快照List
        List<AddNewOrderDetailsDTO> addNewOrderDetailsDTOS = configureNewAddNewOderDetailsList(beforeConfigureNewAddNewProductDetailsDTOS, userId, orderId);
        ////配置购买商品详情快照List 中的orderDetailsId
        List<AddNewProductDetailsDTO> afterConfigureNewAddNewProductDetailsList = afterConfigureNewAddNewProductDetailsList(addNewOrderDetailsDTOS, beforeConfigureNewAddNewProductDetailsDTOS);
        // 获取店铺订单详情价格
        List<BigDecimal> totalList = addNewOrderDetailsDTOS.stream().map(AddNewOrderDetailsDTO::getTotalPrice).toList();
        //计算订单价格
        BigDecimal orderTotalSum = BigDecimal.ZERO;
        for (BigDecimal total : totalList) {
            orderTotalSum = orderTotalSum.add(total);
        }
        BigDecimal finalOrderTotalSum = orderTotalSum;
        return new CreatOrderDTO().setUserId(userId).setBuyDetailsProduct(buyDetailsProduct)
                .setOrderId(orderId).setUserAddressId(userAddressId)
                .setAddNewPayInfoDTO(addNewPayInfoDTO).setOrderToken(orderToken)
                .setAddNewOrderDetailsDTOS(addNewOrderDetailsDTOS).setAfterConfigureNewAddNewProductDetailsList(afterConfigureNewAddNewProductDetailsList)
                .setFinalOrderTotalSum(finalOrderTotalSum);
    }

    /**
     * 扣除商品库存
     *
     * @param buyDetailsProduct 购买商品详情 List
     */
    private void amountDeducted(List<BuyProductDTO> buyDetailsProduct) {
        for (BuyProductDTO buyProductDTO : buyDetailsProduct) {
            // 查询商品库存
            Integer productNumber = productMapper.findProductNumberById(buyProductDTO.getProductId());
            if (productNumber < buyProductDTO.getNumber()) {
                log.info("查询到商品库存不足，库存为：{}", productNumber);
                throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "商品库存不足");
            }
            //扣减商品库存
            productMapper.updateProductNumber(buyProductDTO);
        }
    }

    /**
     * // 获取地址(启用) 用户多个地址，获取启用地址
     *
     * @param userId 用户id
     * @return
     */
    private Long getUserAddressId(Long userId) {
        // 获取地址(启用) 用户多个地址，获取启用地址
        AddressDTO address = addressMapper.getAddressByUserId(userId);
        if (address == null) {
            throw new ServiceException(ServiceCode.ERROR_NOT_FOUND, "用户未绑定地址,请先绑定地址");
        }
        return address.getId();
    }

    /**
     * 配置支付信息
     *
     * @param orderId 订单号
     * @return AddNewPayInfoDTO 新增支付信息DTO
     */
    private AddNewPayInfoDTO configurePayInfo(BigInteger orderId) {
        return new AddNewPayInfoDTO().setPayStatus(PayStatus.PENDING.getCode())
                .setPayType(PayType.UNSELECTED.getCode())
                .setOrderId(orderId)
                .setPayTime(null);
    }

    /**
     * 设置订单token，并存入redis中，30分钟过期,未结束订单的一系列数据销毁
     *
     * @param orderId 订单id
     * @param userId  客户id
     */
    private String addNewOrderToken(BigInteger orderId, Long userId) {
        Map<String, Object> orderMap = new HashMap<>();
        orderMap.put("orderId", orderId);
        try {
            String orderContent = objectMapper.writeValueAsString(orderMap);
            String orderToken = AesCommon.encryptToStr(orderContent, aesKey, aesIv, AesCommon.AES_CBC_PKCS5);
            redissonCommon.setValue("order:token:userId:" + userId, orderToken, TimeUnit.MINUTES.toMillis(30));
            return orderToken;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 配置购买商品详情快照List(前置操作)
     *
     * @param buyProductDTOList 购买商品信息DTO
     * @return List<AddNewProductDetailsDTO>
     */
    private List<AddNewProductDetailsDTO> beforeConfigureNewAddNewProductDetailsList(List<BuyProductDTO> buyProductDTOList) {
        return buyProductDTOList.stream().map(buyProductDTO -> {
            AddNewProductDetailsDTO addNewProductDetailsDTO = new AddNewProductDetailsDTO();
            //通过商品id获取商品信息
            Long productId = buyProductDTO.getProductId();
            ProductDTO productDTO = productMapper.findProductById(productId);
            // 生成购买商品详情记录DTO
            addNewProductDetailsDTO.setName(productDTO.getName())
                    .setNumber(buyProductDTO.getNumber())
                    .setPrice(productDTO.getPrice())
                    .setSupplierId(productDTO.getSupplierId())
                    .setTotalPrice(productDTO.getPrice().multiply(BigDecimal.valueOf(buyProductDTO.getNumber()))); //计算单个购买商品的价格 商品单价 x 商品数量
            return addNewProductDetailsDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 配置商品详情快照List(后置操作)
     * O(n) n为addNewOrderDetailsDTOS + addNewProductDetailsDTOS中元素的总数
     * @param addNewOrderDetailsDTOS   新增订单详情List
     * @param addNewProductDetailsDTOS 新增商品详情List
     * @return List<AddNewProductDetailsDTO>
     */
    private List<AddNewProductDetailsDTO> afterConfigureNewAddNewProductDetailsList(List<AddNewOrderDetailsDTO> addNewOrderDetailsDTOS,
                                                                                    List<AddNewProductDetailsDTO> addNewProductDetailsDTOS) {
        Map<Long, List<AddNewProductDetailsDTO>> productDetailsBySupplierId = addNewProductDetailsDTOS.stream()
                .collect(Collectors.groupingBy(AddNewProductDetailsDTO::getSupplierId));
        for (AddNewOrderDetailsDTO addNewOrderDetailsDTO : addNewOrderDetailsDTOS) {
            Long supplierId = addNewOrderDetailsDTO.getSupplierId();
            List<AddNewProductDetailsDTO> productDetails = productDetailsBySupplierId.get(supplierId);
            if (productDetails!=null){
                for (AddNewProductDetailsDTO productDetail : productDetails) {
                    productDetail.setOrderDetailsId(addNewOrderDetailsDTO.getOrderDetailsId());
                }
            }
        }
        return addNewProductDetailsDTOS;
    }

    /**
     * 配置订单详情快照List
     *
     * @param addNewProductDetailsDTOS 商品详情DTO List
     * @param userId                   用户id
     * @return List<AddNewOrderDetailsDTO> 新增订单详情DTO List
     */
    private List<AddNewOrderDetailsDTO> configureNewAddNewOderDetailsList(List<AddNewProductDetailsDTO> addNewProductDetailsDTOS, Long userId, BigInteger orderId) {
        // 分组和收集数据
        Map<Long, List<AddNewProductDetailsDTO>> groupedBySupplier = addNewProductDetailsDTOS.stream().collect(Collectors.groupingBy(AddNewProductDetailsDTO::getSupplierId));
        // 转换分组后的数据到目标DTO列表
        return groupedBySupplier.entrySet().stream().map(entry -> {
            Long supplierId = entry.getKey();
            List<AddNewProductDetailsDTO> products = entry.getValue();
            // 计算总价格
            BigDecimal totalSum = products.stream()
                    .map(AddNewProductDetailsDTO::getTotalPrice)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // 创建并配置AddNewOrderDetailsDTO
            return new AddNewOrderDetailsDTO().setOrderDetailsId(createOrderDetailsId(userId))
                    .setSupplierId(supplierId)
                    .setTotalPrice(totalSum)
                    .setTotalPrice(totalSum)
                    .setOrderId(orderId);
        }).collect(Collectors.toList());
    }

    /**
     * 配置新增订单DTO
     *
     * @param creatOrderDTO 创建订单DTO
     * @return
     */
    private AddNewOrderDTO configureAddNewOrderDTO(CreatOrderDTO creatOrderDTO) {
        //创建订单数据DTO
        return new AddNewOrderDTO().setId(creatOrderDTO.getOrderId()).setUserId(creatOrderDTO.getUserId())
                .setAddressId(creatOrderDTO.getUserAddressId()).setPayInfoId(creatOrderDTO.getAddNewPayInfoDTO().getId())
                .setOrderStatus(OrderStatus.UNPAID.getCode()).setOrderToken(creatOrderDTO.getOrderToken())
                .setTotalPrice(creatOrderDTO.getFinalOrderTotalSum());
    }

    /**
     * 创建主订单id
     *
     * @param size 详情订单数
     * @return orderId 主订单id
     * 生成主订单编号(20位) = 创建订单时间(10位)+订单详情数(5位)+当天订单序列号(5位)
     */
    private BigInteger createOrderId(int size) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        String formattedDate = sdf.format(new Date());
        // 生成当天订单序列号(5位)
        String GenerateNumber = NumberGenerator.GenerateNumber();
        // 生成主订单编号
        return new BigInteger(formattedDate + String.format("%04d", size) + GenerateNumber);
    }

    // 生成详情订单编号 = 创建详情订单时间(10位)+ 当天订单序列号(5位) + 用户id
    private Long createOrderDetailsId(Long userId) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHH");
        String formattedDate = sdf.format(new Date());
        // 生成当天订单序列号(5位)
        String GenerateNumber = NumberGenerator.GenerateNumber();
        // 生成主订单编号
        return Long.valueOf(formattedDate + userId + GenerateNumber);
    }

}
